#ifndef SPW_COMPLEX_H_
#define SPW_COMPLEX_H_
namespace spwstd {
namespace spwcomplex {

// 通用类型
template<typename ValueT>
struct Complex{
    using ValueType = ValueT; // 萃取使用
    using VT = ValueType;
    // 默认构造函数
    constexpr Complex(const VT& r=VT(), const VT& i=VT())
        : real_(r), imag_(i) {}
    // 复制构造
    constexpr Complex(const Complex&) = default;
    // 复制构造函数
    constexpr Complex& operator=(const Complex&) = default;

    constexpr VT real() const { return real_; }
    constexpr VT imag() const { return imag_; }
    constexpr void real(VT val) { real_ = val; }
    constexpr void imag(VT val) { imag_ = val; }

    // 运算标量
    // 标量复制运算符
    constexpr Complex<VT>& operator=(const VT&);

    constexpr Complex<VT>& 
    operator+=(const VT& t) {
        real_ += t;
        return *this;
    }

    constexpr Complex<VT>& 
    operator-=(const VT& t) {
        real_ -= t;
        return *this;
    }

    constexpr Complex<VT>& operator*=(const VT&);
    constexpr Complex<VT>& operator/=(const VT&);

    // 向上转换 UP <= VT
    // 向上转换复制 UP <= vt, 如果使用类型转换则使用
    // 禁止非初始化隐式转换，向上向下都禁止
    template<typename Up>
    explicit constexpr Complex(const Complex<Up>& z)
        : real_(z.real()), imag_(z.imag()) {}

    template<typename Up> 
    constexpr Complex<VT>& operator=(const Complex<Up>&);
    template<typename Up> 
    constexpr Complex<VT>& operator+=(const Complex<Up>&);
    template<typename Up> 
    constexpr Complex<VT>& operator-=(const Complex<Up>&);
    template<typename Up> 
    constexpr Complex<VT>& operator*=(const Complex<Up>&);
    template<typename Up> 
    constexpr Complex<VT>& operator/=(const Complex<Up>&);

private:
    VT real_; // 实部
    VT imag_; // 虚部
};

// 运算标量
template<typename VT>
constexpr Complex<VT>& Complex<VT>::operator=(const VT& t) {
    real_ = t;
    imag_ = VT();
    return *this;
}

template<typename VT>
constexpr Complex<VT>& Complex<VT>::operator*=(const VT& t) {
    real_ *= t;
    imag_ *= t;
    return *this;
}

template<typename VT>
constexpr Complex<VT>& Complex<VT>::operator/=(const VT& t) {
    real_ /= t;
    imag_ /= t;
    return *this;
}

// 向上转换
template<typename VT>
template<typename Up> 
constexpr Complex<VT>& Complex<VT>::operator=(const Complex<Up>& z) {
    real_ = z.real();
    imag_ = z.imag();
    return *this;
}

template<typename VT>
template<typename Up> 
constexpr Complex<VT>& Complex<VT>::operator+=(const Complex<Up>& z) {
    real_ += z.real();
    imag_ += z.imag();
    return *this;
}

template<typename VT>
template<typename Up> 
constexpr Complex<VT>& Complex<VT>::operator-=(const Complex<Up>& z) {
    real_ -= z.real();
    imag_ -= z.imag();
    return *this;
}

template<typename VT>
template<typename Up> 
constexpr Complex<VT>& Complex<VT>::operator*=(const Complex<Up>& z) {
    const VT r = z.real() * real_ - z.imag() * imag_;
    imag_ = z.real() * imag_ + z.imag() * real_;
    real_ = r;
    return *this;
}

/*
 * R + I    Rr + Ii    rI - iR
 * ----- = --------- + ---------
 * r + i    rr + ii    rr + ii
 * */
template<typename VT>
template<typename Up> 
constexpr Complex<VT>& Complex<VT>::operator/=(const Complex<Up>& z) {
    const VT n = norm(z);
    const VT r = z.real() * real_ + z.imag() * imag_;
    imag_ = (z.real() * imag_ - z.imag() * real_) / n;
    real_ = r / n;
    return *this;
}

// # 二元运算符+-×÷
// ## Complex, Complex
template<typename VT>
constexpr Complex<VT> 
operator+(const Complex<VT>& x, const Complex<VT>& y){
    Complex<VT> r = x;
    r += y;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator-(const Complex<VT>& x, const Complex<VT>& y){
    Complex<VT> r = x;
    r -= y;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator*(const Complex<VT>& x, const Complex<VT>& y){
    Complex<VT> r = x;
    r *= y;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator/(const Complex<VT>& x, const Complex<VT>& y){
    Complex<VT> r = x;
    r /= y;
    return r;
}
// ## Complex, vt

template<typename VT>
constexpr Complex<VT> 
operator+(const Complex<VT>& x, const VT& y){
    Complex<VT> r = x;
    r += y;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator-(const Complex<VT>& x, const VT& y){
    Complex<VT> r = x;
    r -= y;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator*(const Complex<VT>& x, const VT& y){
    Complex<VT> r = x;
    r *= y;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator/(const Complex<VT>& x, const VT& y){
    Complex<VT> r = x;
    r /= y;
    return r;
}

// ## vt, Complex
template<typename VT>
constexpr Complex<VT> 
operator+(const VT& x, const Complex<VT>& y){
    Complex<VT> r = y;
    r += x;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator-(const VT& x, const Complex<VT>& y){
    Complex<VT> r(x);
    r -= y;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator*(const VT& x, const Complex<VT>& y){
    Complex<VT> r(x);
    r *= y;
    return r;
}

template<typename VT>
constexpr Complex<VT> 
operator/(const VT& x, const Complex<VT>& y){
    Complex<VT> r(x);
    r /= y;
    return r;
}

// # 一元运算符
template<typename VT>
constexpr Complex<VT> 
operator+(const Complex<VT>& x){
    return x;
}

template<typename VT>
constexpr Complex<VT> 
operator-(const Complex<VT>& x){
    return Complex<VT>(-x.real(), -x.imag());
}

// # 逻辑运算符
template<typename VT>
constexpr bool operator==(const Complex<VT>& x, const Complex<VT>& y) {
    return x.real()==y.real() && x.imag()==y.imag();
}

template<typename VT>
constexpr bool operator==(const Complex<VT>& x, const VT& y) {
    return x.real()==y && x.imag()==VT();
}

template<typename VT>
constexpr bool operator==(const VT& x, const Complex<VT>& y) {
    return x==y.real() && VT()==y.imag();
}

template<typename VT>
constexpr bool operator!=(const Complex<VT>& x, const Complex<VT>& y) {
    return x.real()!=y.real() || x.imag()!=y.imag();
}

template<typename VT>
constexpr bool operator!=(const Complex<VT>& x, const VT& y) {
    return x.real()!=y || x.imag()!=VT();
}

template<typename VT>
constexpr bool operator!=(const VT& x, const Complex<VT>& y) {
    return x!=y.real() && VT()!=y.imag();
}

// tools
template<typename VT>
constexpr inline VT norm(const Complex<VT>& z) {
    return z.real()*z.real() + z.imag()* z.imag();
}

template<typename VT>
constexpr VT real(const Complex<VT>& z) {
    return z.real();
}

template<typename VT>
constexpr VT imag(const Complex<VT>& z) {
    return z.imag();
}

} // namespace spwcomplex
} // namespace spwstd
#endif
